import {
  Count,
  CountSchema,
  Filter,
  repository,
  Where,
} from '@loopback/repository';
import {
  post,
  param,
  get,
  getFilterSchemaFor,
  getWhereSchemaFor,
  patch,
  put,
  del,
  requestBody,
  HttpErrors
} from '@loopback/rest';
import { ApplyRecord } from '../models';
import { ApplyRecordRepository, UserRepository, ConfigRepository } from '../repositories';
import { authenticate } from '@loopback/authentication';
import { getCurTimestamp } from '../utils/utils';

export class ApplyRecordController {
  constructor(
    @repository(ApplyRecordRepository)
    public applyRecordRepository: ApplyRecordRepository,
    @repository(UserRepository)
    public userRepository: UserRepository,
    @repository(ConfigRepository)
    public configRepository: ConfigRepository,
  ) { }

  @post('/applyRecords', {
    responses: {
      '200': {
        description: 'ApplyRecord model instance',
        content: { 'application/json': { schema: { 'x-ts-type': ApplyRecord } } },
      },
    },
  })
  @authenticate('jwt')
  async create(@requestBody() applyRecord: ApplyRecord): Promise<ApplyRecord> {
    // 判断用户是否可以申请
    let httpError = await this.checkUserApply(applyRecord);
    if (httpError != null) {
      throw httpError;
    }

    applyRecord.createTime = getCurTimestamp()
    return await this.applyRecordRepository.create(applyRecord);
  }

  @get('/applyRecords/count', {
    responses: {
      '200': {
        description: 'ApplyRecord model count',
        content: { 'application/json': { schema: CountSchema } },
      },
    },
  })
  // @authenticate('jwt')
  async count(
    @param.query.object('where', getWhereSchemaFor(ApplyRecord)) where?: Where,
  ): Promise<Count> {
    return await this.applyRecordRepository.count(where);
  }

  @get('/applyRecords', {
    responses: {
      '200': {
        description: 'Array of ApplyRecord model instances',
        content: {
          'application/json': {
            schema: { type: 'array', items: { 'x-ts-type': ApplyRecord } },
          },
        },
      },
    },
  })
  @authenticate('jwt')
  async find(
    @param.query.object('filter', getFilterSchemaFor(ApplyRecord)) filter?: Filter,
  ): Promise<ApplyRecord[]> {
    return await this.applyRecordRepository.find(filter);
  }

  @patch('/applyRecords', {
    responses: {
      '200': {
        description: 'ApplyRecord PATCH success count',
        content: { 'application/json': { schema: CountSchema } },
      },
    },
  })
  @authenticate('jwt')
  async updateAll(
    @requestBody() applyRecord: ApplyRecord,
    @param.query.object('where', getWhereSchemaFor(ApplyRecord)) where?: Where,
  ): Promise<Count> {
    return await this.applyRecordRepository.updateAll(applyRecord, where);
  }

  @get('/applyRecords/{id}', {
    responses: {
      '200': {
        description: 'ApplyRecord model instance',
        content: { 'application/json': { schema: { 'x-ts-type': ApplyRecord } } },
      },
    },
  })
  @authenticate('jwt')
  async findById(@param.path.number('id') id: number): Promise<ApplyRecord> {
    return await this.applyRecordRepository.findById(id);
  }

  @patch('/applyRecords/{id}', {
    responses: {
      '204': {
        description: 'ApplyRecord PATCH success',
      },
    },
  })
  @authenticate('jwt')
  async updateById(
    @param.path.number('id') id: number,
    @requestBody() applyRecord: ApplyRecord,
  ): Promise<void> {
    await this.applyRecordRepository.updateById(id, applyRecord);
  }

  @put('/applyRecords/{id}', {
    responses: {
      '204': {
        description: 'ApplyRecord PUT success',
      },
    },
  })
  @authenticate('jwt')
  async replaceById(
    @param.path.number('id') id: number,
    @requestBody() applyRecord: ApplyRecord,
  ): Promise<void> {
    await this.applyRecordRepository.replaceById(id, applyRecord);
  }

  @del('/applyRecords/{id}', {
    responses: {
      '204': {
        description: 'ApplyRecord DELETE success',
      },
    },
  })
  @authenticate('jwt')
  async deleteById(@param.path.number('id') id: number): Promise<void> {
    await this.applyRecordRepository.deleteById(id);
  }

  // 判断用户申请条件
  async checkUserApply(applyRecord: ApplyRecord): Promise<HttpErrors.HttpError | null> {
    // 免费申请次数是否超过限制
    if (!applyRecord) {
      return null
    }
    let userId = applyRecord.userId || 0
    let user = await this.userRepository.findById(String(userId))
    if (user == null) {
      return new HttpErrors.UnprocessableEntity('用户不存在');  // 用户不存在
    }
    let count = await this.applyRecordRepository.count({userId: userId, createTime: {gte: 1591413939}});
    let confCount = 0
    let vipDays = 0
    let curTimestamp = getCurTimestamp()

    let confApplyLimit = await this.configRepository.findOne({ where: { key: 'FreeApplyLimit' } })
    if (confApplyLimit) {
      confCount = confApplyLimit.value && ~~confApplyLimit.value || 0
    }
    let confVipDays = await this.configRepository.findOne({ where: { key: 'VipDay' } })
    if (confVipDays) {
      vipDays = confVipDays.value && ~~confVipDays.value || 0
    }
    if (count.count >= confCount) {
      if (user.vipTime > 0) {
        if (curTimestamp - user.vipTime > vipDays * 86400) {
          return new HttpErrors.UnprocessableEntity('会员已过期'); // 会员已过期
        } else {
          return null;
        }
      } else {
        return new HttpErrors.UnprocessableEntity('免费申请次数上限，请充值会员'); // 免费申请次数上限，请充值会员
      }
    }
    
    return null;
  }
}
